package structure

import (
	"fmt"

	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/serialize"
	"gddgame.cc/galaxy/utils/uuid"
)

func (execute *Execute) AddTask(conn SafeConn, mapNoId string, from Data, task TaskEvent, data []byte, time int64, params ParamSlice, callback []byte) {
	//先添加
	tid := uuid.RandomString()
	time = execute.FormatTime(time)
	info := &TaskInfo{
		MapNoId:  mapNoId,
		From:     NewBaseDataFrom(from),
		Task:     task,
		Content:  data,
		Time:     time,
		Params:   params,
		Callback: callback,
	}
	slot := serialize.GetSlot()
	if err := slot.Set(info); err != nil {
		fmt.Println("task add err", err)
	}
	b := slot.Bytes()
	conn.AutoRelease(slot)
	d := &BaseData{
		DataType: TaskType,
		Id:       tid,
	}
	execute.CreateBytes(conn, d, b, 0)

	_ = conn.Send("RPUSH", execute.Key+"/task", tid)

	//fmt.Println("push task", tid, execute.CurrentTime())
}

func (execute *Execute) RestoreTask(conn SafeConn, tid string) {
	r, _ := conn.Do("LREM", execute.Key+"/task/executing", 1, tid)
	n := utils.ToInt(utils.ToString(r))
	if n > 0 {
		_ = conn.Send("LPUSH", execute.Key+"/task", tid)
	}
}

func (execute *Execute) FinishTask(conn SafeConn, tid string) {
	r, _ := conn.Do("LREM", execute.Key+"/task/executing", 1, tid)
	n := utils.ToInt(utils.ToString(r))
	if n > 0 {
		execute.Delete(conn, &BaseData{
			DataType: TaskType,
			Id:       tid,
		})
	}
}

func (execute *Execute) PopTask(conn SafeConn) (string, *TaskInfo) {
	r, _ := conn.Do("LPOP", execute.Key+"/task")
	if r == nil {
		return "", nil
	}
	tid := utils.ToString(r)
	m := execute.GetBytes(conn, &BaseData{
		DataType: TaskType,
		Id:       tid,
	})
	info := &TaskInfo{}
	_, _ = info.UnmarshalMsg(m)
	_ = conn.Send("RPUSH", execute.Key+"/task/executing", tid)
	return tid, info
	//var params ParamSlice
	//if v, ok := m["params"]; ok {
	//	params = ParamSlice{}
	//	_, _ = params.UnmarshalMsg(utils.ToBytes(v))
	//}
	//from := NewBaseDataByte(utils.ToBytes(m["from"]))
	//return tid, &TaskInfo{
	//	MapNoId:  utils.ToString(m["mapNoId"]),
	//	From:     from,
	//	Task:     TaskEvent(utils.ToByte(utils.ToString(m["task"]))),
	//	Content:  utils.ToBytes(utils.ToString(m["data"])),
	//	Time:     utils.ToInt64(utils.ToString(m["time"])),
	//	Params:   params,
	//	Callback: utils.ToBytes(utils.ToString(m["callback"])),
	//}
}

func (execute *Execute) PopTasks(conn SafeConn, number int) []*TaskInfo {
	r, _ := conn.Do("EVAL", "local v1 = redis.pcall(\"LRANGE\", KEYS[1], ARGV[1], ARGV[2])\nlocal v2 = 0\nif (v1)\nthen\nv2 = redis.pcall(\"LTRIM\", KEYS[1], ARGV[3], ARGV[4])\nend\nreturn {v1, v2}", 1, execute.Key+"/task", 0, number-1, number, -1)
	if r == nil {
		return nil
	}
	rr := r.([]interface{})
	if len(rr) < 1 {
		//fmt.Println("task", 2, rr)
		return nil
	}
	//fmt.Println("task", 2, rr, utils.ToString(rr[1]) != "OK")
	if utils.ToString(rr[1]) != "OK" {
		return nil
	}
	tid := rr[0].([]interface{})
	if len(tid) == 0 {
		return nil
	}
	sid := utils.ToStringSlice(rr[0])
	//fmt.Println("pop task", sid, execute.CurrentTime())
	taskData := make([]Data, len(sid))
	for index, s := range sid {
		taskData[index] = &BaseData{
			DataType: TaskType,
			Id:       s,
		}
	}
	m := execute.GetBytesBatch(conn, taskData...)
	if m == nil || len(m) == 0 {
		return nil
	}
	//fmt.Println("task", taskData, m)
	info := make([]*TaskInfo, len(m))
	for index, b := range m {
		v := &TaskInfo{}
		_, _ = v.UnmarshalMsg(b)
		info[index] = v
		v.Sid = sid[index]
	}
	args := append([]interface{}{execute.Key + "/task/executing"}, tid...)
	_ = conn.Send("RPUSH", args...)
	return info
}
